// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import zombie.characters.IsoPlayer;
import zombie.characters.IsoZombie;
import zombie.characters.ZombiesZoneDefinition;
import zombie.characters.action.ActionGroup;
import zombie.core.Core;
import zombie.core.Rand;
import zombie.inventory.InventoryItemFactory;
import zombie.inventory.types.HandWeapon;
import zombie.iso.IsoChunk;
import zombie.iso.IsoDirections;
import zombie.iso.IsoGridSquare;
import zombie.iso.IsoMetaChunk;
import zombie.iso.IsoWorld;
import zombie.iso.RoomDef;
import zombie.iso.Vector2;
import zombie.iso.areas.IsoRoom;
import zombie.iso.objects.IsoDeadBody;
import zombie.iso.objects.IsoFireManager;
import zombie.network.GameClient;
import zombie.network.GameServer;
import zombie.network.ServerMap;
import zombie.popman.NetworkZombieSimulator;
import zombie.popman.ZombiePopulationManager;
import zombie.vehicles.PolygonalMap2;

public final class VirtualZombieManager {
    private final ArrayDeque<IsoZombie> ReusableZombies = new ArrayDeque();
    private final HashSet<IsoZombie> ReusableZombieSet = new HashSet();
    private final ArrayList<IsoZombie> ReusedThisFrame = new ArrayList();
    private final ArrayList<IsoZombie> RecentlyRemoved = new ArrayList();
    public static zombie.VirtualZombieManager instance = new zombie.VirtualZombieManager();
    public int MaxRealZombies = 1;
    private final ArrayList<IsoZombie> m_tempZombies = new ArrayList();
    public final ArrayList<IsoGridSquare> choices = new ArrayList();
    private final ArrayList<IsoGridSquare> bestchoices = new ArrayList();
    HandWeapon w = null;
    private int BLOCKED_N = 1;
    private int BLOCKED_S = 2;
    private int BLOCKED_W = 4;
    private int BLOCKED_E = 8;
    private int NO_SQUARE_N = 16;
    private int NO_SQUARE_S = 32;
    private int NO_SQUARE_W = 64;
    private int NO_SQUARE_E = 128;

    public boolean removeZombieFromWorld(IsoZombie z) {
        boolean _boolean = z.getCurrentSquare() != null;
        z.getEmitter().unregister();
        z.removeFromWorld();
        z.removeFromSquare();
        return _boolean;
    }

    private void reuseZombie(IsoZombie isoZombie) {
        if (isoZombie != null) {
            assert !IsoWorld.instance.CurrentCell.getObjectList().contains(isoZombie);

            assert !IsoWorld.instance.CurrentCell.getZombieList().contains(isoZombie);

            assert isoZombie.getCurrentSquare() == null || !isoZombie.getCurrentSquare().getMovingObjects().contains(isoZombie);

            if (!this.isReused(isoZombie)) {
                NetworkZombieSimulator.getInstance().remove(isoZombie);
                isoZombie.resetForReuse();
                this.addToReusable(isoZombie);
            }
        }
    }

    public void addToReusable(IsoZombie z) {
        if (z != null && !this.ReusableZombieSet.contains(z)) {
            this.ReusableZombies.addLast(z);
            this.ReusableZombieSet.add(z);
        }
    }

    public boolean isReused(IsoZombie z) {
        return this.ReusableZombieSet.contains(z);
    }

    public void init() {
        if (!GameClient.bClient) {
            Object object = null;
            if (!IsoWorld.getZombiesDisabled()) {
                for (int _int = 0; _int < this.MaxRealZombies; _int++) {
                    object = new IsoZombie(IsoWorld.instance.CurrentCell);
                    ((IsoZombie)object).getEmitter().unregister();
                    this.addToReusable((IsoZombie)object);
                }
            }
        }
    }

    public void Reset() {
        for (IsoZombie isoZombie : this.ReusedThisFrame) {
            if (isoZombie.vocalEvent != 0L) {
                isoZombie.getEmitter().stopSoundLocal(isoZombie.vocalEvent);
                isoZombie.vocalEvent = 0L;
            }
        }

        this.bestchoices.clear();
        this.choices.clear();
        this.RecentlyRemoved.clear();
        this.ReusableZombies.clear();
        this.ReusableZombieSet.clear();
        this.ReusedThisFrame.clear();
    }

    public void update() {
        long _long = System.currentTimeMillis();

        for (int int0 = this.RecentlyRemoved.size() - 1; int0 >= 0; int0--) {
            IsoZombie isoZombie0 = (IsoZombie)this.RecentlyRemoved.get(int0);
            isoZombie0.updateEmitter();
            if (_long - isoZombie0.removedFromWorldMS > 5000L) {
                if (isoZombie0.vocalEvent != 0L) {
                    isoZombie0.getEmitter().stopSoundLocal(isoZombie0.vocalEvent);
                    isoZombie0.vocalEvent = 0L;
                }

                isoZombie0.getEmitter().stopAll();
                this.RecentlyRemoved.remove(int0);
                this.ReusedThisFrame.add(isoZombie0);
            }
        }

        if (!GameClient.bClient && !GameServer.bServer) {
            for (int int1 = 0; int1 < IsoWorld.instance.CurrentCell.getZombieList().size(); int1++) {
                IsoZombie isoZombie1 = (IsoZombie)IsoWorld.instance.CurrentCell.getZombieList().get(int1);
                if (!isoZombie1.KeepItReal && isoZombie1.getCurrentSquare() == null) {
                    isoZombie1.removeFromWorld();
                    isoZombie1.removeFromSquare();

                    assert this.ReusedThisFrame.contains(isoZombie1);

                    assert !IsoWorld.instance.CurrentCell.getZombieList().contains(isoZombie1);

                    int1--;
                }
            }

            for (int int2 = 0; int2 < this.ReusedThisFrame.size(); int2++) {
                IsoZombie isoZombie2 = (IsoZombie)this.ReusedThisFrame.get(int2);
                this.reuseZombie(isoZombie2);
            }

            this.ReusedThisFrame.clear();
        } else {
            for (int int3 = 0; int3 < this.ReusedThisFrame.size(); int3++) {
                IsoZombie isoZombie3 = (IsoZombie)this.ReusedThisFrame.get(int3);
                this.reuseZombie(isoZombie3);
            }

            this.ReusedThisFrame.clear();
        }
    }

    public IsoZombie createRealZombieAlways(int ZombieDir, boolean bDead) {
        return this.createRealZombieAlways(ZombieDir, bDead, 0);
    }

    public IsoZombie createRealZombieAlways(int descriptorID, int ZombieDir, boolean bDead) {
        int _int = zombie.PersistentOutfits.instance.getOutfit(descriptorID);
        return this.createRealZombieAlways(ZombieDir, bDead, _int);
    }

    public IsoZombie createRealZombieAlways(int ZombieDir, boolean bDead, int outfitID) {
        IsoZombie isoZombie = null;
        if (!zombie.SystemDisabler.doZombieCreation) {
            return null;
        } else if (this.choices != null && !this.choices.isEmpty()) {
            IsoGridSquare isoGridSquare = (IsoGridSquare)this.choices.get(Rand.Next(this.choices.size()));
            if (isoGridSquare == null) {
                return null;
            } else {
                if (this.w == null) {
                    this.w = (HandWeapon)InventoryItemFactory.CreateItem("Base.Axe");
                }

                if ((GameServer.bServer || GameClient.bClient) && outfitID == 0) {
                    outfitID = ZombiesZoneDefinition.pickPersistentOutfit(isoGridSquare);
                }

                if (this.ReusableZombies.isEmpty()) {
                    isoZombie = new IsoZombie(IsoWorld.instance.CurrentCell);
                    isoZombie.bDressInRandomOutfit = outfitID == 0;
                    isoZombie.setPersistentOutfitID(outfitID);
                    IsoWorld.instance.CurrentCell.getObjectList().add(isoZombie);
                } else {
                    isoZombie = (IsoZombie)this.ReusableZombies.removeFirst();
                    this.ReusableZombieSet.remove(isoZombie);
                    isoZombie.getHumanVisual().clear();
                    isoZombie.clearAttachedItems();
                    isoZombie.clearItemsToSpawnAtDeath();
                    isoZombie.bDressInRandomOutfit = outfitID == 0;
                    isoZombie.setPersistentOutfitID(outfitID);
                    isoZombie.setSitAgainstWall(false);
                    isoZombie.setOnDeathDone(false);
                    isoZombie.setOnKillDone(false);
                    isoZombie.setDoDeathSound(true);
                    isoZombie.setHitTime(0);
                    isoZombie.setFallOnFront(false);
                    isoZombie.setFakeDead(false);
                    isoZombie.setReanimatedPlayer(false);
                    isoZombie.setStateMachineLocked(false);
                    Vector2 vector2 = isoZombie.dir.ToVector();
                    vector2.x = vector2.x + ((float)Rand.Next(200) / 100.0F - 0.5F);
                    vector2.y = vector2.y + ((float)Rand.Next(200) / 100.0F - 0.5F);
                    vector2.normalize();
                    isoZombie.setForwardDirection(vector2);
                    IsoWorld.instance.CurrentCell.getObjectList().add(isoZombie);
                    isoZombie.walkVariant = "ZombieWalk";
                    isoZombie.DoZombieStats();
                    if (isoZombie.isOnFire()) {
                        IsoFireManager.RemoveBurningCharacter(isoZombie);
                        isoZombie.setOnFire(false);
                    }

                    if (isoZombie.AttachedAnimSprite != null) {
                        isoZombie.AttachedAnimSprite.clear();
                    }

                    isoZombie.thumpFlag = 0;
                    isoZombie.thumpSent = false;
                    isoZombie.soundSourceTarget = null;
                    isoZombie.soundAttract = 0.0F;
                    isoZombie.soundAttractTimeout = 0.0F;
                    isoZombie.bodyToEat = null;
                    isoZombie.eatBodyTarget = null;
                    isoZombie.atlasTex = null;
                    isoZombie.clearVariables();
                    isoZombie.setStaggerBack(false);
                    isoZombie.setKnockedDown(false);
                    isoZombie.setKnifeDeath(false);
                    isoZombie.setJawStabAttach(false);
                    isoZombie.setCrawler(false);
                    isoZombie.initializeStates();
                    isoZombie.actionContext.setGroup(ActionGroup.getActionGroup("zombie"));
                    isoZombie.advancedAnimator.OnAnimDataChanged(false);
                    isoZombie.setDefaultState();
                    isoZombie.getAnimationPlayer().resetBoneModelTransforms();
                }

                isoZombie.dir = IsoDirections.fromIndex(ZombieDir);
                isoZombie.setForwardDirection(isoZombie.dir.ToVector());
                isoZombie.getInventory().setExplored(false);
                if (bDead) {
                    isoZombie.bDressInRandomOutfit = true;
                }

                isoZombie.target = null;
                isoZombie.TimeSinceSeenFlesh = 100000.0F;
                if (!isoZombie.isFakeDead()) {
                    if (zombie.SandboxOptions.instance.Lore.Toughness.getValue() == 1) {
                        isoZombie.setHealth(3.5F + Rand.Next(0.0F, 0.3F));
                    }

                    if (zombie.SandboxOptions.instance.Lore.Toughness.getValue() == 2) {
                        isoZombie.setHealth(1.5F + Rand.Next(0.0F, 0.3F));
                    }

                    if (zombie.SandboxOptions.instance.Lore.Toughness.getValue() == 3) {
                        isoZombie.setHealth(0.5F + Rand.Next(0.0F, 0.3F));
                    }

                    if (zombie.SandboxOptions.instance.Lore.Toughness.getValue() == 4) {
                        isoZombie.setHealth(Rand.Next(0.5F, 3.5F) + Rand.Next(0.0F, 0.3F));
                    }
                } else {
                    isoZombie.setHealth(0.5F + Rand.Next(0.0F, 0.3F));
                }

                float float0 = (float)Rand.Next(0, 1000);
                float float1 = (float)Rand.Next(0, 1000);
                float0 /= 1000.0F;
                float1 /= 1000.0F;
                float0 += (float)isoGridSquare.getX();
                float1 += (float)isoGridSquare.getY();
                isoZombie.setCurrent(isoGridSquare);
                isoZombie.setMovingSquareNow();
                isoZombie.setX(float0);
                isoZombie.setY(float1);
                isoZombie.setZ((float)isoGridSquare.getZ());
                if ((GameClient.bClient || GameServer.bServer) && isoZombie.networkAI != null) {
                    isoZombie.networkAI.reset();
                }

                isoZombie.upKillCount = true;
                if (bDead) {
                    isoZombie.setDir(IsoDirections.fromIndex(Rand.Next(8)));
                    isoZombie.setForwardDirection(isoZombie.dir.ToVector());
                    isoZombie.setFakeDead(false);
                    isoZombie.setHealth(0.0F);
                    isoZombie.upKillCount = false;
                    isoZombie.DoZombieInventory();
                    new IsoDeadBody(isoZombie, true);
                    return isoZombie;
                } else {
                    synchronized (IsoWorld.instance.CurrentCell.getZombieList()) {
                        isoZombie.getEmitter().register();
                        IsoWorld.instance.CurrentCell.getZombieList().add(isoZombie);
                        if (GameClient.bClient) {
                            isoZombie.bRemote = true;
                        }

                        if (GameServer.bServer) {
                            isoZombie.OnlineID = ServerMap.instance.getUniqueZombieId();
                            if (isoZombie.OnlineID == -1) {
                                IsoWorld.instance.CurrentCell.getZombieList().remove(isoZombie);
                                IsoWorld.instance.CurrentCell.getObjectList().remove(isoZombie);
                                this.ReusedThisFrame.add(isoZombie);
                                return null;
                            }

                            ServerMap.instance.ZombieMap.put(isoZombie.OnlineID, isoZombie);
                        }

                        return isoZombie;
                    }
                }
            }
        } else {
            return null;
        }
    }

    private IsoGridSquare pickEatingZombieSquare(float float2, float float3, float float1, float float0, int _int) {
        IsoGridSquare isoGridSquare = IsoWorld.instance.CurrentCell.getGridSquare((double)float1, (double)float0, (double)_int);
        if (isoGridSquare == null || !this.canSpawnAt(isoGridSquare.x, isoGridSquare.y, isoGridSquare.z) || isoGridSquare.HasStairs()) {
            return null;
        } else {
            return PolygonalMap2.instance.lineClearCollide(float2, float3, float1, float0, _int, null, false, true) ? null : isoGridSquare;
        }
    }

    public void createEatingZombies(IsoDeadBody target, int nb) {
        if (!IsoWorld.getZombiesDisabled()) {
            for (int _int = 0; _int < nb; _int++) {
                float float0 = target.x;
                float float1 = target.y;
                switch (_int) {
                    case 0:
                        float0 -= 0.5F;
                        break;
                    case 1:
                        float0 += 0.5F;
                        break;
                    case 2:
                        float1 -= 0.5F;
                        break;
                    case 3:
                        float1 += 0.5F;
                }

                IsoGridSquare isoGridSquare = this.pickEatingZombieSquare(target.x, target.y, float0, float1, (int)target.z);
                if (isoGridSquare != null) {
                    this.choices.clear();
                    this.choices.add(isoGridSquare);
                    IsoZombie isoZombie = this.createRealZombieAlways(1, false);
                    if (isoZombie != null) {
                        zombie.ZombieSpawnRecorder.instance.record(isoZombie, "createEatingZombies");
                        isoZombie.bDressInRandomOutfit = true;
                        isoZombie.setX(float0);
                        isoZombie.setY(float1);
                        isoZombie.setZ(target.z);
                        isoZombie.faceLocationF(target.x, target.y);
                        isoZombie.setEatBodyTarget(target, true);
                    }
                }
            }
        }
    }

    private IsoZombie createRealZombie(int _int, boolean _boolean) {
        return GameClient.bClient ? null : this.createRealZombieAlways(_int, _boolean);
    }

    public void AddBloodToMap(int nSize, IsoChunk chk) {
        for (int int0 = 0; int0 < nSize; int0++) {
            Object object = null;
            int int1 = 0;

            do {
                int int2 = Rand.Next(10);
                int int3 = Rand.Next(10);
                object = chk.getGridSquare(int2, int3, 0);
                int1++;
            } while (int1 < 100 && (object == null || !((IsoGridSquare)object).isFree(false)));

            if (object != null) {
                byte _byte = 5;
                if (Rand.Next(10) == 0) {
                    _byte = 10;
                }

                if (Rand.Next(40) == 0) {
                    _byte = 20;
                }

                for (int int4 = 0; int4 < _byte; int4++) {
                    float float0 = (float)Rand.Next(3000) / 1000.0F;
                    float float1 = (float)Rand.Next(3000) / 1000.0F;
                    chk.addBloodSplat(
                        (float)((IsoGridSquare)object).getX() + --float0,
                        (float)((IsoGridSquare)object).getY() + --float1,
                        (float)((IsoGridSquare)object).getZ(),
                        Rand.Next(12) + 8
                    );
                }
            }
        }
    }

    public ArrayList<IsoZombie> addZombiesToMap(int nSize, RoomDef room) {
        return this.addZombiesToMap(nSize, room, true);
    }

    public ArrayList<IsoZombie> addZombiesToMap(int nSize, RoomDef room, boolean bAllowDead) {
        ArrayList arrayList = new ArrayList();
        if ("Tutorial".equals(Core.GameMode)) {
            return arrayList;
        } else if (IsoWorld.getZombiesDisabled()) {
            return arrayList;
        } else {
            this.choices.clear();
            this.bestchoices.clear();
            Object object = null;

            for (int int0 = 0; int0 < room.rects.size(); int0++) {
                int int1 = room.level;
                RoomDef.RoomRect roomRect = (RoomDef.RoomRect)room.rects.get(int0);

                for (int int2 = roomRect.x; int2 < roomRect.getX2(); int2++) {
                    for (int int3 = roomRect.y; int3 < roomRect.getY2(); int3++) {
                        object = IsoWorld.instance.CurrentCell.getGridSquare(int2, int3, int1);
                        if (object != null && this.canSpawnAt(int2, int3, int1)) {
                            this.choices.add(object);
                            boolean _boolean = false;

                            for (int int4 = 0; int4 < IsoPlayer.numPlayers; int4++) {
                                if (IsoPlayer.players[int4] != null && ((IsoGridSquare)object).isSeen(int4)) {
                                    _boolean = true;
                                }
                            }

                            if (!_boolean) {
                                this.bestchoices.add(object);
                            }
                        }
                    }
                }
            }

            nSize = Math.min(nSize, this.choices.size());
            if (!this.bestchoices.isEmpty()) {
                this.choices.addAll(this.bestchoices);
                this.choices.addAll(this.bestchoices);
            }

            for (int int5 = 0; int5 < nSize; int5++) {
                if (!this.choices.isEmpty()) {
                    room.building.bAlarmed = false;
                    int int6 = Rand.Next(8);
                    byte _byte = 4;
                    IsoZombie isoZombie = this.createRealZombie(int6, bAllowDead ? Rand.Next(_byte) == 0 : false);
                    if (isoZombie != null && isoZombie.getSquare() != null) {
                        if (!GameServer.bServer) {
                            isoZombie.bDressInRandomOutfit = true;
                        }

                        isoZombie.setX((float)((int)isoZombie.getX()) + (float)Rand.Next(2, 8) / 10.0F);
                        isoZombie.setY((float)((int)isoZombie.getY()) + (float)Rand.Next(2, 8) / 10.0F);
                        this.choices.remove(isoZombie.getSquare());
                        this.choices.remove(isoZombie.getSquare());
                        this.choices.remove(isoZombie.getSquare());
                        arrayList.add(isoZombie);
                    }
                } else {
                    System.out.println("No choices for zombie.");
                }
            }

            this.bestchoices.clear();
            this.choices.clear();
            return arrayList;
        }
    }

    public void tryAddIndoorZombies(RoomDef room, boolean bAllowDead) {
    }

    private void addIndoorZombies(int int4, RoomDef roomDef, boolean _boolean) {
        this.choices.clear();
        this.bestchoices.clear();
        Object object = null;

        for (int int0 = 0; int0 < roomDef.rects.size(); int0++) {
            int int1 = roomDef.level;
            RoomDef.RoomRect roomRect = (RoomDef.RoomRect)roomDef.rects.get(int0);

            for (int int2 = roomRect.x; int2 < roomRect.getX2(); int2++) {
                for (int int3 = roomRect.y; int3 < roomRect.getY2(); int3++) {
                    object = IsoWorld.instance.CurrentCell.getGridSquare(int2, int3, int1);
                    if (object != null && this.canSpawnAt(int2, int3, int1)) {
                        this.choices.add(object);
                    }
                }
            }
        }

        int4 = Math.min(int4, this.choices.size());
        if (!this.bestchoices.isEmpty()) {
            this.choices.addAll(this.bestchoices);
            this.choices.addAll(this.bestchoices);
        }

        for (int int5 = 0; int5 < int4; int5++) {
            if (!this.choices.isEmpty()) {
                roomDef.building.bAlarmed = false;
                int int6 = Rand.Next(8);
                byte _byte = 4;
                IsoZombie isoZombie = this.createRealZombie(int6, _boolean ? Rand.Next(_byte) == 0 : false);
                if (isoZombie != null && isoZombie.getSquare() != null) {
                    zombie.ZombieSpawnRecorder.instance.record(isoZombie, "addIndoorZombies");
                    isoZombie.bIndoorZombie = true;
                    isoZombie.setX((float)((int)isoZombie.getX()) + (float)Rand.Next(2, 8) / 10.0F);
                    isoZombie.setY((float)((int)isoZombie.getY()) + (float)Rand.Next(2, 8) / 10.0F);
                    this.choices.remove(isoZombie.getSquare());
                    this.choices.remove(isoZombie.getSquare());
                    this.choices.remove(isoZombie.getSquare());
                }
            } else {
                System.out.println("No choices for zombie.");
            }
        }

        this.bestchoices.clear();
        this.choices.clear();
    }

    public void addIndoorZombiesToChunk(IsoChunk chunk, IsoRoom room, int zombieCountForRoom, ArrayList<IsoZombie> zombies) {
        if (zombieCountForRoom > 0) {
            float _float = room.getRoomDef().getAreaOverlapping(chunk);
            int int0 = (int)Math.ceil((double)((float)zombieCountForRoom * _float));
            if (int0 > 0) {
                this.choices.clear();
                int int1 = room.def.level;

                for (int int2 = 0; int2 < room.rects.size(); int2++) {
                    RoomDef.RoomRect roomRect = (RoomDef.RoomRect)room.rects.get(int2);
                    int int3 = Math.max(chunk.wx * 10, roomRect.x);
                    int int4 = Math.max(chunk.wy * 10, roomRect.y);
                    int int5 = Math.min((chunk.wx + 1) * 10, roomRect.x + roomRect.w);
                    int int6 = Math.min((chunk.wy + 1) * 10, roomRect.y + roomRect.h);

                    for (int int7 = int3; int7 < int5; int7++) {
                        for (int int8 = int4; int8 < int6; int8++) {
                            IsoGridSquare isoGridSquare = chunk.getGridSquare(int7 - chunk.wx * 10, int8 - chunk.wy * 10, int1);
                            if (isoGridSquare != null && this.canSpawnAt(int7, int8, int1)) {
                                this.choices.add(isoGridSquare);
                            }
                        }
                    }
                }

                if (!this.choices.isEmpty()) {
                    room.def.building.bAlarmed = false;
                    int0 = Math.min(int0, this.choices.size());

                    for (int int9 = 0; int9 < int0; int9++) {
                        IsoZombie isoZombie = this.createRealZombie(Rand.Next(8), false);
                        if (isoZombie != null && isoZombie.getSquare() != null) {
                            if (!GameServer.bServer) {
                                isoZombie.bDressInRandomOutfit = true;
                            }

                            isoZombie.setX((float)((int)isoZombie.getX()) + (float)Rand.Next(2, 8) / 10.0F);
                            isoZombie.setY((float)((int)isoZombie.getY()) + (float)Rand.Next(2, 8) / 10.0F);
                            this.choices.remove(isoZombie.getSquare());
                            zombies.add(isoZombie);
                        }
                    }

                    this.choices.clear();
                }
            }
        }
    }

    public void addIndoorZombiesToChunk(IsoChunk chunk, IsoRoom room) {
        if (room.def.spawnCount == -1) {
            room.def.spawnCount = this.getZombieCountForRoom(room);
        }

        this.m_tempZombies.clear();
        this.addIndoorZombiesToChunk(chunk, room, room.def.spawnCount, this.m_tempZombies);
        zombie.ZombieSpawnRecorder.instance.record(this.m_tempZombies, "addIndoorZombiesToChunk");
    }

    public void addDeadZombiesToMap(int nSize, RoomDef room) {
        boolean boolean0 = false;
        this.choices.clear();
        this.bestchoices.clear();
        Object object = null;

        for (int int0 = 0; int0 < room.rects.size(); int0++) {
            int int1 = room.level;
            RoomDef.RoomRect roomRect = (RoomDef.RoomRect)room.rects.get(int0);

            for (int int2 = roomRect.x; int2 < roomRect.getX2(); int2++) {
                for (int int3 = roomRect.y; int3 < roomRect.getY2(); int3++) {
                    object = IsoWorld.instance.CurrentCell.getGridSquare(int2, int3, int1);
                    if (object != null && ((IsoGridSquare)object).isFree(false)) {
                        this.choices.add(object);
                        if (!GameServer.bServer) {
                            boolean boolean1 = false;

                            for (int int4 = 0; int4 < IsoPlayer.numPlayers; int4++) {
                                if (IsoPlayer.players[int4] != null && ((IsoGridSquare)object).isSeen(int4)) {
                                    boolean1 = true;
                                }
                            }

                            if (!boolean1) {
                                this.bestchoices.add(object);
                            }
                        }
                    }
                }
            }
        }

        nSize = Math.min(nSize, this.choices.size());
        if (!this.bestchoices.isEmpty()) {
            this.choices.addAll(this.bestchoices);
            this.choices.addAll(this.bestchoices);
        }

        for (int int5 = 0; int5 < nSize; int5++) {
            if (!this.choices.isEmpty()) {
                int int6 = Rand.Next(8);
                this.createRealZombie(int6, true);
            }
        }

        this.bestchoices.clear();
        this.choices.clear();
    }

    public void RemoveZombie(IsoZombie obj) {
        if (obj.isReanimatedPlayer()) {
            if (obj.vocalEvent != 0L) {
                obj.getEmitter().stopSoundLocal(obj.vocalEvent);
                obj.vocalEvent = 0L;
            }

            zombie.ReanimatedPlayers.instance.removeReanimatedPlayerFromWorld(obj);
        } else {
            if (obj.isDead()) {
                if (!this.RecentlyRemoved.contains(obj)) {
                    obj.removedFromWorldMS = System.currentTimeMillis();
                    this.RecentlyRemoved.add(obj);
                }
            } else if (!this.ReusedThisFrame.contains(obj)) {
                this.ReusedThisFrame.add(obj);
            }
        }
    }

    public void createHordeFromTo(float spawnX, float spawnY, float targetX, float targetY, int count) {
        ZombiePopulationManager.instance.createHordeFromTo((int)spawnX, (int)spawnY, (int)targetX, (int)targetY, count);
    }

    public IsoZombie createRealZombie(float x, float y, float z) {
        this.choices.clear();
        this.choices.add(IsoWorld.instance.CurrentCell.getGridSquare((double)x, (double)y, (double)z));
        if (!this.choices.isEmpty()) {
            int _int = Rand.Next(8);
            return this.createRealZombie(_int, true);
        } else {
            return null;
        }
    }

    public IsoZombie createRealZombieNow(float x, float y, float z) {
        this.choices.clear();
        IsoGridSquare isoGridSquare = IsoWorld.instance.CurrentCell.getGridSquare((double)x, (double)y, (double)z);
        if (isoGridSquare == null) {
            return null;
        } else {
            this.choices.add(isoGridSquare);
            if (!this.choices.isEmpty()) {
                int _int = Rand.Next(8);
                return this.createRealZombie(_int, false);
            } else {
                return null;
            }
        }
    }

    private int getZombieCountForRoom(IsoRoom isoRoom) {
        if (IsoWorld.getZombiesDisabled()) {
            return 0;
        } else if (GameClient.bClient) {
            return 0;
        } else if (Core.bLastStand) {
            return 0;
        } else {
            int int0 = 7;
            if (zombie.SandboxOptions.instance.Zombies.getValue() == 1) {
                int0 = 3;
            } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 2) {
                int0 = 4;
            } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 3) {
                int0 = 6;
            } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 5) {
                int0 = 15;
            }

            float _float = 0.0F;
            IsoMetaChunk isoMetaChunk = IsoWorld.instance.getMetaChunk(isoRoom.def.x / 10, isoRoom.def.y / 10);
            if (isoMetaChunk != null) {
                _float = isoMetaChunk.getLootZombieIntensity();
                if (_float > 4.0F) {
                    int0 = (int)((float)int0 - (_float / 2.0F - 2.0F));
                }
            }

            if (isoRoom.def.getArea() > 100) {
                int0 -= 2;
            }

            int0 = Math.max(2, int0);
            if (isoRoom.getBuilding() != null) {
                int int1 = isoRoom.def.getArea();
                if (isoRoom.getBuilding().getRoomsNumber() > 100 && int1 >= 20) {
                    int int2 = isoRoom.getBuilding().getRoomsNumber() - 95;
                    if (int2 > 20) {
                        int2 = 20;
                    }

                    if (zombie.SandboxOptions.instance.Zombies.getValue() == 1) {
                        int2 += 10;
                    } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 2) {
                        int2 += 7;
                    } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 3) {
                        int2 += 5;
                    } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 4) {
                        int2 -= 10;
                    }

                    if (int1 < 30) {
                        int2 -= 6;
                    }

                    if (int1 < 50) {
                        int2 -= 10;
                    }

                    if (int1 < 70) {
                        int2 -= 13;
                    }

                    return Rand.Next(int2, int2 + 10);
                }
            }

            if (Rand.Next(int0) == 0) {
                int int3 = 1;
                int3 = (int)((float)int3 + (_float / 2.0F - 2.0F));
                if (isoRoom.def.getArea() < 30) {
                    int3 -= 4;
                }

                if (isoRoom.def.getArea() > 85) {
                    int3 += 2;
                }

                if (isoRoom.getBuilding().getRoomsNumber() < 7) {
                    int3 -= 2;
                }

                if (zombie.SandboxOptions.instance.Zombies.getValue() == 1) {
                    int3 += 3;
                } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 2) {
                    int3 += 2;
                } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 3) {
                    int3++;
                } else if (zombie.SandboxOptions.instance.Zombies.getValue() == 5) {
                    int3 -= 2;
                }

                int3 = Math.max(0, int3);
                int3 = Math.min(7, int3);
                return Rand.Next(int3, int3 + 2);
            } else {
                return 0;
            }
        }
    }

    public void roomSpotted(IsoRoom room) {
        if (!GameClient.bClient) {
            room.def.forEachChunk((roomDef, isoChunk) -> isoChunk.addSpawnedRoom(roomDef.ID));
            if (room.def.spawnCount == -1) {
                room.def.spawnCount = this.getZombieCountForRoom(room);
            }

            if (room.def.spawnCount > 0) {
                if (room.getBuilding().getDef().isFullyStreamedIn()) {
                    ArrayList arrayList = this.addZombiesToMap(room.def.spawnCount, room.def, false);
                    zombie.ZombieSpawnRecorder.instance.record(arrayList, "roomSpotted");
                } else {
                    this.m_tempZombies.clear();
                    room.def.forEachChunk((var2x, isoChunk) -> this.addIndoorZombiesToChunk(isoChunk, room, room.def.spawnCount, this.m_tempZombies));
                    zombie.ZombieSpawnRecorder.instance.record(this.m_tempZombies, "roomSpotted");
                }
            }
        }
    }

    private int getBlockedBits(IsoGridSquare isoGridSquare) {
        int _int = 0;
        if (isoGridSquare == null) {
            return _int;
        } else {
            if (isoGridSquare.nav[IsoDirections.N.index()] == null) {
                _int |= this.NO_SQUARE_N;
            } else if (IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 1, 0, 1)) {
                _int |= this.BLOCKED_N;
            }

            if (isoGridSquare.nav[IsoDirections.S.index()] == null) {
                _int |= this.NO_SQUARE_S;
            } else if (IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 1, 2, 1)) {
                _int |= this.BLOCKED_S;
            }

            if (isoGridSquare.nav[IsoDirections.W.index()] == null) {
                _int |= this.NO_SQUARE_W;
            } else if (IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 0, 1, 1)) {
                _int |= this.BLOCKED_W;
            }

            if (isoGridSquare.nav[IsoDirections.E.index()] == null) {
                _int |= this.NO_SQUARE_E;
            } else if (IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 2, 1, 1)) {
                _int |= this.BLOCKED_E;
            }

            return _int;
        }
    }

    private boolean isBlockedInAllDirections(int int0, int int1, int int2) {
        IsoGridSquare isoGridSquare = GameServer.bServer
            ? ServerMap.instance.getGridSquare(int0, int1, int2)
            : IsoWorld.instance.CurrentCell.getGridSquare(int0, int1, int2);
        if (isoGridSquare == null) {
            return false;
        } else {
            boolean boolean0 = IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 1, 0, 1) && isoGridSquare.nav[IsoDirections.N.index()] != null;
            boolean boolean1 = IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 1, 2, 1) && isoGridSquare.nav[IsoDirections.S.index()] != null;
            boolean boolean2 = IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 0, 1, 1) && isoGridSquare.nav[IsoDirections.W.index()] != null;
            boolean boolean3 = IsoGridSquare.getMatrixBit(isoGridSquare.pathMatrix, 2, 1, 1) && isoGridSquare.nav[IsoDirections.E.index()] != null;
            return boolean0 && boolean1 && boolean2 && boolean3;
        }
    }

    private boolean canPathOnlyN(IsoGridSquare isoGridSquare) {
        while (true) {
            int _int = this.getBlockedBits(isoGridSquare);
            if ((_int & (this.BLOCKED_W | this.BLOCKED_E)) != (this.BLOCKED_W | this.BLOCKED_E)) {
                return false;
            }

            if ((_int & this.NO_SQUARE_N) != 0) {
                return false;
            }

            if ((_int & this.BLOCKED_N) != 0) {
                return true;
            }

            isoGridSquare = isoGridSquare.nav[IsoDirections.N.index()];
        }
    }

    private boolean canPathOnlyS(IsoGridSquare isoGridSquare) {
        while (true) {
            int _int = this.getBlockedBits(isoGridSquare);
            if ((_int & (this.BLOCKED_W | this.BLOCKED_E)) != (this.BLOCKED_W | this.BLOCKED_E)) {
                return false;
            }

            if ((_int & this.NO_SQUARE_S) != 0) {
                return false;
            }

            if ((_int & this.BLOCKED_S) != 0) {
                return true;
            }

            isoGridSquare = isoGridSquare.nav[IsoDirections.S.index()];
        }
    }

    private boolean canPathOnlyW(IsoGridSquare isoGridSquare) {
        while (true) {
            int _int = this.getBlockedBits(isoGridSquare);
            if ((_int & (this.BLOCKED_N | this.BLOCKED_S)) != (this.BLOCKED_N | this.BLOCKED_S)) {
                return false;
            }

            if ((_int & this.NO_SQUARE_W) != 0) {
                return false;
            }

            if ((_int & this.BLOCKED_W) != 0) {
                return true;
            }

            isoGridSquare = isoGridSquare.nav[IsoDirections.W.index()];
        }
    }

    private boolean canPathOnlyE(IsoGridSquare isoGridSquare) {
        while (true) {
            int _int = this.getBlockedBits(isoGridSquare);
            if ((_int & (this.BLOCKED_N | this.BLOCKED_S)) != (this.BLOCKED_N | this.BLOCKED_S)) {
                return false;
            }

            if ((_int & this.NO_SQUARE_E) != 0) {
                return false;
            }

            if ((_int & this.BLOCKED_E) != 0) {
                return true;
            }

            isoGridSquare = isoGridSquare.nav[IsoDirections.E.index()];
        }
    }

    public boolean canSpawnAt(int x, int y, int z) {
        IsoGridSquare isoGridSquare = IsoWorld.instance.CurrentCell.getGridSquare(x, y, z);
        if (isoGridSquare != null && isoGridSquare.isFree(false)) {
            int _int = this.getBlockedBits(isoGridSquare);
            if (_int == (this.BLOCKED_N | this.BLOCKED_S | this.BLOCKED_W | this.BLOCKED_E)) {
                return false;
            } else {
                return (_int & (this.BLOCKED_N | this.BLOCKED_S)) == (this.BLOCKED_N | this.BLOCKED_S)
                        && this.canPathOnlyW(isoGridSquare)
                        && this.canPathOnlyE(isoGridSquare)
                    ? false
                    : (_int & (this.BLOCKED_W | this.BLOCKED_E)) != (this.BLOCKED_W | this.BLOCKED_E)
                        || !this.canPathOnlyN(isoGridSquare)
                        || !this.canPathOnlyS(isoGridSquare);
            }
        } else {
            return false;
        }
    }

    public int reusableZombiesSize() {
        return this.ReusableZombies.size();
    }
}
